
import * as globes from "./globes.js";
import {ø} from "../util/objects.js";
import {$} from "../util/seq.js";

const factories = ø(globes);  // create an object containing just the enumerable kv pairs of the module

export const globeTypes = new Set(Object.keys(factories));

/**
 * @param globeAgent
 * @param {Handle} projection_type
 * @param {Handle} orientation
 * @param viewboxAgent
 */
export function defineGlobeBuilder(globeAgent, projection_type, orientation, viewboxAgent) {

    function updateOrientation(globe, orientation) {
        // CONSIDER: Ideally, the globe object keeps itself up to date given the orientation, projection, and viewbox,
        // and the inputController and renderer do not need to update the projection or pass in the viewbox.
        // The globe essentially becomes a wrapper of the viewbox, which can propagate it throughout the engine stack.

        globe?.setOrientation(orientation, viewboxAgent.value());
    }

    function build(projection_type) {
        const globe = factories[projection_type]?.(viewboxAgent.value());
        updateOrientation(globe, orientation.get());
        globeAgent.submit(globe ?? Promise.reject(`Unknown projection: ${projection_type}`));
    }

    projection_type.on($`change`, build);
    orientation.on($`change`, orientation => updateOrientation(globeAgent.value(), orientation));

    // When the viewbox changes, rebuild globe using the new view size.
    // CONSIDER: why rebuild the globe when the viewbox changes? shouldn't this just be a call to setOrientation?
    viewboxAgent.on($`update`, () => build(projection_type.get()));
}
